#include <sys/types.h>
#include <pthread.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <cutils/properties.h>
#include "myjni.h"
#include "platform_config.h"

#define IP_ADDR "192.168.43.1"
#define PORT 54321
#define BUFFER_MAX    1024  /* input buffer for commands */
#define TOKEN_MAX     32     /* max number of arguments in buffer */
#define REPLY_MAX     1024   /* largest reply allowed */
//#undef LOGE
//#undef ALOGE
//#define LOGE(arg...)
//#define ALOGE(arg...)
extern SysInf  SysInfor;
extern int priv_fd;
extern volatile int flag_login, flag_newIp;
extern char iccid[PROPERTY_VALUE_MAX];
extern u32 g_currentAdValue;
extern volatile int gps_state;
extern int localSocketR, localSocketW;
static int running  = 0;
int work_button = 0, pesticidesLiter_button = 0;
struct cmdinfo {
    const char *name;
    unsigned numargs;
    int (*func)(char **arg, char reply[REPLY_MAX]);
};

static int adValue(char **arg, char reply[REPLY_MAX])
{
    sprintf(reply, "replayAdValue=%u", g_currentAdValue);
    return 0;
}

static int readParameter(char **arg, char reply[REPLY_MAX])
{
    SysInf *p = &SysInfor;
    stru_Linear *lt = p->str_linearList;
    
    memset(reply, 0, REPLY_MAX);
    snprintf(reply, REPLY_MAX, "replyParameter %s %hd %s %s %s %hu %hu %hu %hu %hu %hu %hu %hu %hu %hu %hd %hd %hd %hd %hd %hd %hd %hd end", p->IP, p->port, p->terminalID, p->CarNumber_utf8, iccid, lt[0].adValue, lt[1].adValue, lt[2].adValue, lt[3].adValue, lt[4].adValue, lt[0].literOfliquor, lt[1].literOfliquor, lt[2].literOfliquor, lt[3].literOfliquor, lt[4].literOfliquor, p->EMPTY_AD_VALUE, p->FULL_AD_VALUE, p->EMPTY_COUNTER_VALUE, p->STEP_DECEND_NUMBER, p->AD_VALUE_BASE, p->PER_STEPDECEND_ADVALUE, p->WORKING_WIDTH, p->CALC_AREA_DELAY_SECONDS);

    return 0;
}

static int setParameter(char **arg, char reply[REPLY_MAX])
{
    int i = 0;
    SysInf sysinfo = SysInfor;
    SysInf *p = &sysinfo;

    stru_Linear *lt = p->str_linearList;

    if (strcmp(arg[23], "end"))
            goto out;

    while (arg[i]) {
        LOGE("arg[%d]=%s", i, arg[i]);
        i++;
    }
    if (strcmp(p->IP, arg[0]) || (p->port != atoi(arg[1]))) {
        flag_login = 0;
        flag_newIp = 1;
    }
    strcpy(p->IP, arg[0]);
    p->port = atoi(arg[1]);
    strcpy(p->terminalID, arg[2]);
    strcpy(p->CarNumber_utf8, arg[3]);
    //strcpy(ccid, arg[4]);
    lt[0].adValue = atoi(arg[5]);
    lt[1].adValue = atoi(arg[6]);
    lt[2].adValue = atoi(arg[7]);
    lt[3].adValue = atoi(arg[8]);
    lt[4].adValue = atoi(arg[9]);
    lt[0].literOfliquor = atoi(arg[10]);
    lt[1].literOfliquor = atoi(arg[11]);
    lt[2].literOfliquor = atoi(arg[12]);
    lt[3].literOfliquor = atoi(arg[13]);
    lt[4].literOfliquor = atoi(arg[14]);
    p->EMPTY_AD_VALUE = atoi(arg[15]);
    p->FULL_AD_VALUE = atoi(arg[16]);
    p->EMPTY_COUNTER_VALUE = atoi(arg[17]);
    p->STEP_DECEND_NUMBER = atoi(arg[18]);
    p->AD_VALUE_BASE = atoi(arg[19]);
    p->PER_STEPDECEND_ADVALUE = atoi(arg[20]);
    p->WORKING_WIDTH= atoi(arg[21]);
	p->CALC_AREA_DELAY_SECONDS = atoi(arg[22]);
    sprintf((char*)p->LocalPhoneNum1,"01861%s", (char*)p->terminalID);

    int unicode;
    char *p_int = (char *)&unicode;
    int u_len = UTF8toUnicode((unsigned char *)arg[3], &unicode);
    sprintf(p->CarNumber + 2, "%s", arg[3] + u_len);
    p->CarNumber[sizeof(p->CarNumber) - 1] = 0; //防止参数过长溢出
    p->CarNumber[0] = p_int[1];
    p->CarNumber[1] = p_int[0];

    if (memcmp((void *)p, (void *)&SysInfor, sizeof(SysInf))) {
        SysInfor = sysinfo;
        at24c64Write(priv_fd, SYSINFO_SET, (void *)p, SysInfLength);
    }
    strcpy(reply, "okay");
    reply[4] = 0;

    return 0;

out:
    strcpy(reply, "error");
    reply[5] = 0;

    return 0;
}

static int reinitParameter(char **arg, char reply[REPLY_MAX])
{
    reinitAt24c64();
    strcpy(reply, "okay");
    reply[5] = 0;
    return 0;
}

void *restart_thread(void * arg) {
    sleep(1);
    system("reboot");
    return NULL;
}

static int restart(char **arg, char reply[REPLY_MAX])
{
    if (strcmp(arg[0], "3699"))//restart device need a password
        goto out;
    pthread_t thread;
    pthread_create(&thread, NULL, restart_thread, NULL);
    strcpy(reply, "okay");
    reply[5] = 0;
    return 0;
out:
    strcpy(reply, "error");
    reply[5] = 0;

    return 0;
}

static int workStatus(char **arg, char reply[REPLY_MAX])
{
    sprintf(reply, "replyWorkStatus %d %d", gps_state, flag_login);
    reply[5] = 0;
    return 0;
}

struct cmdinfo cmds[] = {
    { "adValue",                   0,  adValue },
    { "readParameter",             0,  readParameter },
    { "setParameter",             24,  setParameter },
    { "reinitParameter",           0,  reinitParameter },
    { "restart",                   1,  restart },
    { "workStatus",                0,  workStatus },
};

static int readx(int s, void *_buf, int count)
{
    char *buf = _buf;
    int n = 0, r;
    if (count < 0) return -1; 
    while (n < count) {
        r = read(s, buf + n, count - n); 
        if (r < 0) {
            if (errno == EINTR) continue;
            ALOGE("read error: %s\n", strerror(errno));
            return -1; 
        }
        if (r == 0) {
            ALOGE("eof\n");
            return -1; /* EOF */
        }
        n += r;
    }   
    return 0;
}

static int writex(int s, const void *_buf, int count)
{
    const char *buf = _buf;
    int n = 0, r;
    if (count < 0) return -1; 
    while (n < count) {
        r = write(s, buf + n, count - n); 
        if (r < 0) {
            if (errno == EINTR) continue;
            ALOGE("write error: %s\n", strerror(errno));
            return -1; 
        }
        n += r;
    }   
    return 0;
}


/* Tokenize the command buffer, locate a matching command,
 * ensure that the required number of arguments are provided,
 * call the function(), return the result.
 */
static int execute(int s, char cmd[BUFFER_MAX])
{
    char reply[REPLY_MAX];
    char *arg[TOKEN_MAX+1];
    unsigned i;
    unsigned n = 0;
    unsigned short count;
    int ret = -1;

    ALOGE("execute('%s')\n", cmd);

        /* default reply is "" */
    reply[0] = 0;

        /* n is number of args (not counting arg[0]) */
    arg[0] = cmd;
    while (*cmd) {
        if (isspace(*cmd)) {
            *cmd++ = 0;
            n++;
            arg[n] = cmd;
            if (n == TOKEN_MAX) {
                ALOGE("too many arguments\n");
                goto done;
            }
        }
        cmd++;
    }

    for (i = 0; i < sizeof(cmds) / sizeof(cmds[0]); i++) {
        if (!strcmp(cmds[i].name,arg[0])) {
            if (n != cmds[i].numargs) {
                ALOGE("%s requires %d arguments (%d given)\n",
                     cmds[i].name, cmds[i].numargs, n);
            } else {
                ret = cmds[i].func(arg + 1, reply);
            }
            goto done;
        }
    }
    ALOGE("unsupported command '%s'\n", arg[0]);

done:
    if (reply[0]) {
        n = snprintf(cmd, BUFFER_MAX, "%s", reply);
    } else {
        n = snprintf(cmd, BUFFER_MAX, "%d", ret);
    }
    if (n > BUFFER_MAX) n = BUFFER_MAX;
    count = n;

    // ALOGI("reply: '%s'\n", cmd);
    if (writex(s, &count, sizeof(count))) return -1;
    if (writex(s, cmd, count)) return -1;
    return 0;
}


#if 1
void *translate_data(void * arg) {
    int bytes;
    char buf[BUFFER_MAX];
    int s = (int)arg;

    while (running) {
        fd_set fds;
        struct timeval tv; 
        int r;
        FD_ZERO (&fds);
        FD_SET (s, &fds);
        tv.tv_sec = 7; 
        tv.tv_usec = 0;

        //LOGE("%s select", __func__);
        r = select(s+1, &fds, NULL, NULL, &tv);
        //LOGE("%s select out, r=%d, errno[%d]=%s", __func__, r, errno, strerror(errno));
        if (-1 == r) {
            if (EINTR == errno)
                continue;
            LOGE("%s select", __func__);
        }
        if (0 == r) {
            LOGE( "select timeout\n");
            break; 
        }
        if (FD_ISSET(s, &fds)) {
            unsigned short count;
            if (readx(s, &count, sizeof(count))) {
                ALOGE("failed to read size\n");
                break;
            }
            if ((count < 1) || (count >= BUFFER_MAX)) {
                ALOGE("invalid size %d\n", count);
                break;
            }
            if (readx(s, buf, count)) {
                ALOGE("failed to read command\n");
                break;
            }
            buf[count] = 0;
            //LOGE("%s buf=%s", __func__, buf);
            if (execute(s, buf)) break;
        }
    }  
out:
    LOGE("%s thread exit", __func__);
    close(s);
    return NULL;
}
#endif
int calc_area_delay_seconds = -1;

static void calcAreaDelayTimer(void) {
    calc_area_delay_seconds = 0;
}


static int irq_detect_fd = -1;
#define BUTTON_ON 0
#define PESTICIDESLITER_IRQ 0
#define BUTTON_IRQ 1
#define POWER_DET_IRQ 2
long pesticidesLiter_button_timer = 0, work_button_timer = 0;
void irq_detect_work() {
    int ret, value = 0;
    int stop_work = 0;
    int led;
    long timer;
    int irq, gpio_value;
    int work;
    
    if (irq_detect_fd < 0)
        return;

    ret = read(irq_detect_fd, &value, sizeof(value));
    if (ret != sizeof(value))
        return;

    LOGE("%s", __func__);
    timer = currentTimeInSec();
    irq = value&0x03;
    gpio_value = (value >> 2) & 0x01;
    if (irq == PESTICIDESLITER_IRQ) {//药水箱开关量
        //if (labs(pesticidesLiter_button_timer - timer) < 10)//10秒以内的视为无效
        //    return;
        pesticidesLiter_button_timer = timer; 
        if (gpio_value == BUTTON_ON) {
            pesticidesLiter_button = 1;
            calc_area_delay_seconds = -1;
        } else {
            pesticidesLiter_button = 0;
            if (SysInfor.CALC_AREA_DELAY_SECONDS > 0 && work_button == 0)//如果工作按钮没打开，停止喷药后延时30秒计算面积
                calcAreaDelayTimer();
        }
    } else if (irq == BUTTON_IRQ) {//工作按钮
        //if (labs(work_button_timer - timer) < 10)
        //    return;
        work_button_timer = timer;
        if (gpio_value == BUTTON_ON) {
            led = 1;
            work_button = 1;
        } else {
            led = 0;
            work_button = 0;
 	    LOGE("按下结束按钮");
            stop_work = 1;
        }
        write(irq_detect_fd, &led, sizeof(led));//控制按钮led灯
    } else if (irq == POWER_DET_IRQ) {//车辆熄火检测，计算面积
        if (gpio_value == 1) {//检测到高电平表示熄火
	 LOGE("检测电源掉");
           //stop_work = 1;
	 g_power_del_counter = 1;
        }
    }
    if (stop_work) {//停止工作，开始计算面积
        work = STOP_WORK;
        write(localSocketW, &work, sizeof(work));
    } 
}

static void power_detect_irq(int signum) { //按键和药水箱开关量检测
    int value = IRQ_DETECT;
    write(localSocketW, &value, sizeof(value));
}


int power_detect_signal(void) {
    irq_detect_fd = open(POWER_DETECT_PATH, O_RDWR);
    if (irq_detect_fd < 0) {
        printf("open %s fail err=%s\n", POWER_DETECT_PATH, strerror(errno));
        return -1; 
    }
    irq_detect_work();//开机控制一次led按键
    signal(SIGIO, power_detect_irq);
    fcntl(irq_detect_fd, F_SETOWN, getpid());
    fcntl(irq_detect_fd, F_SETFL, fcntl(irq_detect_fd, F_GETFL) | FASYNC);

    return irq_detect_fd;
}


void close_power_detect(void) {
    if (irq_detect_fd > 0)
        close(irq_detect_fd);
}

static int wifiApStart = 0;
void *listenWifiAp(void * arg)
{
    int fd, s, struct_len;
    struct sockaddr_in server_addr;
    struct sockaddr_in client_addr;
    char buf[BUFFER_MAX];
    void *result;

    if (wifiApStart)
        return NULL;

    wifiApStart = 1;
    running = 1;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(PORT);
    server_addr.sin_addr.s_addr = INADDR_ANY;
    //inet_pton(AF_INET, IP_ADDR, &server_addr.sin_addr);
    bzero(&(server_addr.sin_zero), 8);
    struct_len = sizeof(struct sockaddr_in);

    fd = socket(AF_INET, SOCK_STREAM, 0);
    while(bind(fd, (struct sockaddr *)&server_addr, struct_len) == -1) {
        LOGE("%s fail to bind err=%s\n", __func__, strerror(errno));
        sleep(5);
    };
    LOGE("%s Bind Success!\n", __func__);
    while(listen(fd, 5) == -1) {
        LOGE("%s fail to listen err=%s\n", __func__, strerror(errno));
        sleep(5);
    };
    while (running) {
        LOGE("%s Listening....\n", __func__);
        s = accept(fd, (struct sockaddr *)&client_addr, &struct_len);
        if (s < 0) {
            LOGE("%s accept err=%s", __func__, strerror(errno));
            break;
        }
        LOGE("%s Get the Client.\n", __func__);
        pthread_t thread;
        pthread_create(&thread, NULL, translate_data, (void *)s);
        pthread_join(thread, &result);
        ALOGE("%s close fd", __func__);
    }
    close(fd);
    return NULL;
}
